package Java_Concurrency_in_Practice.c5_6;

import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;

import Java_Concurrency_in_Practice.futureTask.Preloader;

public class Memoizer4<A, V> implements Computable<A, V> {
	
	private final Map<A, Future<V>> cache = new ConcurrentHashMap<A, Future<V>>();
	
	private final Computable<A, V> c;
	
	public Memoizer4(Computable<A, V> c) {
		this.c = c;
	}

	@Override
	public synchronized V compute(final A arg) throws InterruptedException {
		while (true) {
			Future<V> f = cache.get(arg);
			if (f == null) {
				Callable<V> eval = new Callable<V>() {
					@Override
					public V call() throws Exception {
						return c.compute(arg);
					}
				};
				FutureTask<V> ft = new FutureTask<V>(eval);
				f = cache.putIfAbsent(arg, ft);
				if (f == null) {
					f = ft;
					ft.run(); // 在这里将调用c.compute
				}
			}
			try {
				return f.get();
			} catch (Exception e) {
				cache.remove(arg, f);
				Preloader.launderThrowable(e);
			}
			return null;
		}
	}

}
